package com.tiecode.pastejava;

import com.rapid.framework.data.convertion.ToStringConverter;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.parser.JavacParser;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;
import com.tiecode.compiler.api.process.Elements;

public class JavaCodeConverter implements ToStringConverter<String> {
    private Elements elements;
    private int tab;

    public JavaCodeConverter(Elements elements, int tab) {
        this.elements = elements;
        this.tab = tab;
    }

    @Override
    public String convert(String text) {
        String result = convertStatement(text);
        if (result == null) {
            result = convertClassMembers(text);
        }
        return result;
    }

    private String convertStatement(String text) {
        Context context = new Context();
        JavacFileManager.preRegister(context);
        ParserFactory factory = ParserFactory.instance(context);
        try {
            text = "{" + text + "}";
            JavacParser parser = factory.newParser(text,
                    false, false, false);
            JCTree tree = parser.parseStatement();
            StringBuilder builder = new StringBuilder();
            new Java2TiecodePrinter(elements, tab).scan(tree, builder);
            return decodeUnicode(builder.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private String convertClassMembers(String text) {
        Context context = new Context();
        JavacFileManager.preRegister(context);
        ParserFactory factory = ParserFactory.instance(context);
        try {
            if (!text.contains("import ")) {
                text = "class __Root {" + text + "}";
            }
            JavacParser parser = factory.newParser(text,
                    false, false, false);
            JCTree.JCCompilationUnit unit = parser.parseCompilationUnit();
            StringBuilder builder = new StringBuilder();
            for (JCTree def : unit.defs) {
                new Java2TiecodePrinter(elements, tab).scan(def, builder);
                builder.append("\n");
            }
            return decodeUnicode(builder.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decodeUnicode(String unicodeStr) {
        if (unicodeStr == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        int i = 0;
        while (i < unicodeStr.length()) {
            char c = unicodeStr.charAt(i);
            if (c == '\\' && i + 1 < unicodeStr.length() && unicodeStr.charAt(i + 1) == 'u') {
                int value = 0;
                if (i + 5 < unicodeStr.length()) {
                    for (int j = 0; j < 4; j++) {
                        char ch = unicodeStr.charAt(i + 2 + j);
                        switch (ch) {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                value = (value << 4) + (ch - '0');
                                break;
                            case 'a':
                            case 'b':
                            case 'c':
                            case 'd':
                            case 'e':
                            case 'f':
                                value = (value << 4) + 10 + (ch - 'a');
                                break;
                            case 'A':
                            case 'B':
                            case 'C':
                            case 'D':
                            case 'E':
                            case 'F':
                                value = (value << 4) + 10 + (ch - 'A');
                                break;
                            default:
                                throw new IllegalArgumentException("Invalid Unicode sequence: " + unicodeStr.substring(i, i + 6));
                        }
                    }
                    sb.append((char) value);
                    i += 6;
                } else {
                    throw new IllegalArgumentException("Invalid Unicode sequence: " + unicodeStr.substring(i));
                }
            } else {
                sb.append(c);
                i++;
            }
        }
        return sb.toString();
    }
}
